package ru.compft.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * User: VVasiliev
 * Date: 18.08.2011
 * Time: 11:54:28
 */
public class JAXBUtils {
    private static final Logger logger = LoggerFactory.getLogger(JAXBUtils.class);

    /**
     * Get context for JAXB Objects by context path
     *
     * @param context - specific context path
     * @return - JAXBContext
     * @throws javax.xml.bind.JAXBException
     */
    private static JAXBContext getContext(String context) throws JAXBException {
        return JAXBContext.newInstance(context, JAXBUtils.class.getClassLoader());
    }

    /**
     * Get context for JAXB Objects by class
     *
     * @return - JAXBContext
     * @throws javax.xml.bind.JAXBException
     */
    private static JAXBContext getContext(Class cls) throws JAXBException {
        return JAXBContext.newInstance(cls);
    }

    /**
     * Marshalling Object into OutputStream in the form of XML
     *
     * @param o       - object
     * @param context - JAXBContext
     * @param os      - OutputStream
     */
    public static void marshalling(Object o, String context, OutputStream os) {
        try {
            final Marshaller marshaller = getContext(context).createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_ENCODING, GlobalConstants.JAXB_ENCODING);
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            //        marshaller.setProperty("jaxb.fragment", Boolean.TRUE); //
            marshaller.marshal(o, os);
        } catch (JAXBException e) {
            logger.error("Exception while marshalling(). Context=" + context, e);
        }
    }

    /**
     * Marshalling Object into OutputStream in the form of XML
     *
     * @param o  - object
     * @param os - OutputStream
     */
    public static void marshalling(Object o, Class cls, OutputStream os) {
        try {
            final Marshaller marshaller = getContext(cls).createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_ENCODING, GlobalConstants.JAXB_ENCODING);
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            //        marshaller.setProperty("jaxb.fragment", Boolean.TRUE); //
            marshaller.marshal(o, os);
        } catch (JAXBException e) {
            logger.error("Exception while marshalling. Class=" + cls, e);
        }
    }

    /**
     * Unmarshalling Object from XML InputStream
     *
     * @param context - JAXBContext
     * @param in      - InputStream
     */
    public static Object unmarshalling(String context, InputStream in) {
        try {
            Unmarshaller u = getContext(context).createUnmarshaller();
            return u.unmarshal(in);
        } catch (JAXBException e) {
            logger.error("Exception while unmarshalling. Context=" + context, e);
        }
        return null;
    }

    /**
     * Unmarshalling Object from XML InputStream
     *
     * @param in - InputStream
     */
    public static Object unmarshalling(Class cls, InputStream in) {
        try {
            Unmarshaller u = getContext(cls).createUnmarshaller();
            return u.unmarshal(in);
        } catch (JAXBException e) {
            logger.error("Exception while unmarshalling. Class=" + cls, e);
        }
        return null;
    }
}
